home *** CD-ROM | disk | FTP | other *** search
- /* contour - find contours of a tabulated function of two variables
-
- history...
- 28 Jun 86 Printing output file name.
- Optionally listing tiles visited.
- 26 Jun 86 User may specify a voltage and get estimated
- capacitance per unit length.
-
- bugs...
- Needs better approximation for the true location of a contour
- than a linear interpolation?
-
- method...
- The rectangular grid is divided into triangles, or "tiles",
- numbered as follows:
-
- (xmin,ymin) (xmax,ymin)
- ------------------------------- ----------
- | 0 /| 2 /| 4 /| 6 /| 8 /| /|2w-2/|
- | / | / | / | / | / | / | / |
- | / | / | / | / | / | | / |
- | / | / | / | / | / | / | / |
- |/ 1 |/ 3 |/ 5 |/ 7 |/ 9 |/ |/2w-1|
- --------------------------------- -------
- | 2w /|2w+2/| /| /| /| /|
- | / | / | / | / | / | / |
- | / | / | / | / | / |
- | / | / | / | / | /
- |/2w+1|/ |/ |/
- -------------------
- | /| /| ...
-
- |/ |/ |/ |/ |
- ------------------------------
- /| /| /| /| /| /|
- / | / | / | / | / | / |
- | / | / | / | / | / | / |
- | / | / | / | / | / | / |
- |/ |/ |/ |/ |/ |2hw-1|
- -----------------------------------------
- (xmax,ymax)
-
- Each tile is assigned edge numbers as follows:
-
- 2
- ------- /|
- | / / |
- | / / |
- 1 | / 0 0 / | 1
- | / / |
- | / / |
- | / / |
- |/ -------
- 2
-
- For each contour level, MAIN scans the grid to find a triangle
- that the contour crosses, then calls FOLLOW. FOLLOW follows
- the contour, marking each tile it crosses, until it leaves the
- grid or closes on itself. For each tile crossed, FOLLOW calls
- RECORD_POINT which calculates the point at which the contour
- leaves the tile (using linear interpolation) and records it in
- a stack. MAIN prints the stack contents in reverse order and,
- if the contour left the grid, calls FOLLOW again and prints the
- points along the rest of the contour.
-
- timing...
- this .bat file:
- time <cr >>times
- contour v.pot -n 3
- time <cr >>times
-
- gave these timings:
- Current time is 13:25:55.80
-
- Current time is 13:27:47.63 -> 1.8619
- Current time is 13:36:45.47
-
- Current time is 13:38:25.56 -> 1.6691 changed tests in crosses()
-
- Current time is 14:11:03.38
-
- Current time is 14:12:43.15 -> 1.6602 eliminated a multiply in record_point()
-
- */
-
- #include <stdio.h>
- #include <math.h>
-
- int next_edge[6]={2,0,1,1,2,0};
- int etest[6];
- int next_tile[3];
-
- #define VERSION "0.2"
-
- #define maximum(a,b) (a)>(b)?(a):(b)
- #define BUFSIZE 128
- #define LEFT_SIDE(t) ((t)%w2==0)
- #define RIGHT_SIDE(t) ((t)%w2==w2-3)
- #define TOP_SIDE(t) (!((t)&1)&&(t<w2))
- #define BOTTOM_SIDE(t) (((t)&1) && ((t)>=bottom_row))
-
- double adjust();
-
- double xmin;
- double ymin;
- double xmax;
- double ymax;
- double xp,yp; /* last points sent to output file */
- double zmin=1.e30;
- double zmax=-1.e30;
- double ex,ey; /* grid spacing in x and y direction */
- double slope; /* ey/ex */
- double *x; /* pointer to data area for contour x values */
- double *y; /* pointer to data area for contour y values */
- double *z; /* pointer to data area for tabulated heights */
- double xscale,yscale,zscale;
- double aspect,correct,eps;
- double z1; /* minimum z contour value */
- double z2; /* maximum z contour value */
- double adj; /* scale factor for printing contour value */
- double integral; /* integral of gradient along a contour */
- double voltage; /* voltage between boundaries given in -v switch */
-
- int contours=6; /* number of contour levels */
- int debugging=0;
- int calculating_capacitance=0; /* nonzero if user specified voltage */
- int continuing; /* zero on 1st call to record_point() for each contour */
- int error; /* code returned by fprintf() */
- int h; /* height of grid in cells */
- int w; /* width of grid in cells */
- int w2; /* w * 2 */
- int hw; /* height*width */
- int hw2; /* height*width*2 */
- int bottom_row; /* tile number for first tile in bottom row */
- int kind=0; /* nonzero for log contours */
- int np=0; /* number of contour points stored so far */
- int num_points=0; /* number of contour points which can be stored */
- z_arguments=0; /* # arguments of -z switch */
- char outname[40]="out.cnt";
- char *mark; /* nonzero if this tile has been visited */
- char buf[BUFSIZE]; /* text I/O buffer */
- char format[50]; /* format for printing scale factor */
-
- FILE file;
- FILE ofile;
-
-
- main(argc,argv) int argc; char **argv;
- { int i,j,k,xx,yy,zz,xx2,yy2,rlz,t,e,t0,e0,more;
- double yval,h0,h1,h2;
- char *s;
- double zval;
-
- read_data(argc,argv);
- /*
- attributes();
- show_z();
- */
- etest[0]=0;
- etest[1]=1;
- etest[2]=w;
- etest[3]=w+1;
- etest[4]=w;
- etest[5]=1;
- next_tile[0]=1;
- next_tile[1]=-1;
- next_tile[2]=1-2*w;
-
- rlz=contours+2;
- scale_one(zmin,zmax,&z1,&z2,rlz,&contours,kind);
- #ifdef xxx
- printf("main: zmin=%f zmax=%f kind=%d \n", zmin, zmax, kind);
- printf("main: z1=%f z2=%f contours=%d \n",z1,z2,contours);
- #endif
-
- if(!kind) adj=adjust(format,z1,z2,contours);
- zval=z2;
- for(i=0; i<=contours; i++,zval -= (z2-z1)/contours)
- {if(!kind) sprintf(buf,format,zval*adj);
- else sprintf(buf," 1e%1.0f",zval);
- printf("contour level %s",buf);
- /*
- if(zval<=zmin || zval>=zmax) continue;
- */
- for (t=0; t<hw2; t++) mark[t]=0; /* clear all marks */
- for (t=0; t<hw2-w2; t++)
- {integral=0.;
- if(t%w2==w2-2)
- {t++;
- continue; /* skip phantom tiles along right edge */
- }
- if(!mark[t] && crosses(t,zval))
- {if(t&1) h0=z[t/2+w+1]; else h0=z[t/2];
- h1=z[t/2+1]; h2=z[t/2+w];
- if(h0<zval && zval<=h1) e=2;
- else if (h1<zval && zval<=h2) e=0;
- else e=1;
- t0=t;
- continuing=0;
- /* printf("main: picking up %g contour at tile %d, edge %d\n",zval,t,e); */
- more=follow(t,e,1,zval);
- if(more)
- {for (j=np; j; )
- {j--;
- error=fprintf(ofile,"%8.3g %8.3g\n",x[j],y[j]);
- if(error==-1) quit();
- }
- xp=x[0]; yp=y[0];
- /* we'll now be going opposite direction along contour... */
- integral= -integral;
- np=0;
- if(h1<zval && zval<=h0) e=2;
- else if (h2<zval && zval<=h1) e=0;
- else e=1;
- /* printf("main: restarting %g contour at tile %d, edge %d\n",zval,t0,e); */
- follow(t0,e,0,zval);
- integral= -integral;
- flush_contour(zval);
- }
- else flush_contour(zval);
- }
- } /* all cells checked for this contour level */
- }
- fclose(ofile);
- }
-
- follow(t,e,high_on_left,zval) int t,e,high_on_left; double zval;
- { int test;
- while(1)
- {if(debugging)
- printf("contour entering tile %3d, edge %d %11s with high ground on %s\n",
- t,e,
- (e==0)?"(DIAGONAL),"
- :((t&1)?
- ((e==1)?"(LEFT),":"(BOTTOM),")
- :((e==1)?"(RIGHT),":"(TOP),")
- ),
- high_on_left?"LEFT":"RIGHT");
- if(t&1) /* lower right triangle */
- test=etest[e+3];
- else /* upper left triangle */
- test=etest[e];
- if(high_on_left ^ (z[t/2+test]>zval)) e=next_edge[e+3];
- else e=next_edge[e];
- record_point(t,e,zval);
- if((e==1 && (LEFT_SIDE(t) || RIGHT_SIDE(t))) ||
- (e==2 && (TOP_SIDE(t) || BOTTOM_SIDE(t))) ) return 1;
- if(t&1) t -= next_tile[e];
- else t += next_tile[e];
- if(mark[t]) return 0;
- mark[t]++;
- }
- }
-
- attributes()
- { printf("tile attributes...\n");
- int j,k,m;
- char type[9];
- m=0;
- for (k=0; k<h-1; k++)
- {for (j=0; j<w2-2; j++)
- {type[0]=0;
- if(LEFT_SIDE(m)) strcat(type,"L");
- if (TOP_SIDE(m)) strcat(type,"T");
- if (RIGHT_SIDE(m)) strcat(type,"R");
- if (BOTTOM_SIDE(m)) strcat(type,"B");
- printf("%2s ",type);
- m++;
- }
- printf("\n");
- m += 2;
- }
- }
-
- show_z()
- { int i,j,k=0;
- printf("h=%d w=%d\n",h,w);
- for (i=0; i<h; i++)
- {for (j=0; j<w; j++)
- printf("%5.2f ",z[k++]);
- printf("\n");
- }
- }
-
- record_point(t,e,zval) int t,e; double zval;
- { double xt,yt,xc,yc,d,f=0.,dist,dx,dy;
- int t5,t5w;
- t5=t/2;
- t5w=t5+w;
- /* printf("record_point: tile %d edge %d zval %8.2g",t,e,zval); */
- if(np==num_points)
- {xt=x[np-1]; yt=y[np-1];
- flush_contour(z);
- x[0]=xt; y[0]=yt; np++;
- }
-
- if(t&1) /* lower triangle */
- {switch(e)
- {case 2:
- d=z[t5w]-z[t5w+1];
- dx=-d*slope;
- dy=(z[t5w+1]-z[t5+1]);
- if(d) f=(z[t5w]-zval)/d;
- xc=t5%w+f; yc=t5/w+1;
- break;
- case 1:
- d=z[t5+1]-z[t5w+1];
- dx=(z[t5w+1]-z[t5w])*slope;
- dy=-d;
- if(d) f=(z[t5+1]-zval)/d;
- xc=t5%w+1; yc=t5/w+f;
- break;
- case 0:
- d=z[t5+1]-z[t5w];
- dx=(z[t5w+1]-z[t5w])*slope;
- dy=(z[t5w+1]-z[t5+1]);
- if(d) f=(z[t5+1]-zval)/d;
- xc=t5%w+1.-f; yc=t5/w+f;
- break;
- }
- }
- else /* upper triangle */
- {switch(e)
- {case 2:
- d=z[t5]-z[t5+1];
- dx=-d*slope;
- dy=(z[t5w]-z[t5]);
- if(d) f=(z[t5]-zval)/d;
- xc=t5%w+f; yc=t5/w;
- break;
- case 1:
- d=z[t5]-z[t5w];
- dx=(z[t5+1]-z[t5])*slope;
- dy=-d;
- if(d) f=(z[t5]-zval)/d;
- xc=t5%w; yc=t5/w+f;
- break;
- case 0:
- d=z[t5+1]-z[t5w];
- dx=(z[t5+1]-z[t5])*slope;
- dy=(z[t5w]-z[t5]);
- if(d) f=(z[t5+1]-zval)/d;
- xc=t5%w+1.-f; yc=t5/w+f;
- break;
- }
- }
- x[np]=xt=xc*ex+xmin;
- y[np]=yt=yc*ey+ymin;
- if(continuing)
- integral += dx*(yt-yp)-dy*(xt-xp);
- else
- continuing=1;
- /* dx=xp-xt; dy=yp-yt; dist=dx*dx+dy*dy;
- if(dist>eps) */
- np++;
- xp=xt; yp=yt;
- /* printf(" x,y=(%7.2g,%7.2g)\n",x[np],y[np]); */
- }
-
- crosses(t,zval) int t; double zval;
- { int gt=0, le=0;
- if(z[t/2+1]<zval) gt=1; else le=1;
- if(z[t/2+w]<zval) gt=1; else le=1;
- if(t&1)
- {if(z[t/2+w+1]<zval) gt=1; else le=1;
- }
- else
- {if(z2=z[t/2]<zval) gt=1; else le=1;
- }
- return (gt&le);
- /*
- int does_cross;
- does_cross=(gt&le);
- printf("crosses: contour at %g %s cross tile %d (%4.2f, %4.2f, %4.2f)\n",
- zval,does_cross?"DOES":"DOES NOT",t,z[t/2+1],z[t/2+w],z2);
- return does_cross;
- */
- }
-
- read_data(argc,argv) int argc; char **argv;
- { int i,j,k,length;
- double xx,yy,d,*pd,sum;
- char *s,*t;
-
- if(argc>1 && streq(argv[1],"?")) help();
- if(argc<=1 || *argv[1]=='-') file=stdin;
- else
- {if(argc>1)
- {argc--; argv++; /* advance to file name */
- file=fopen(*argv,"r");
- if(file==0) {printf("file %s not found\n",*argv); exit();}
- strcpy(outname,*argv);
- if(s=index(outname,'.')) *s=0;
- strcat(outname,".cnt");
- }
- else help();
- }
- argc--; argv++; /* advance to first switch if any */
- while(argc>0)
- {i=get_parameter(argc,argv);
- argv=argv+i; argc=argc-i;
- }
- ofile=fopen(outname,"w");
- if(ofile==0) {printf("can\'t create output file\n"); exit(1);}
- /*
- sample data file header...
- 0. 3. 10 minimum and maximum y values, width of grid
- 0. 3. 10 minimum and maximum y values, height of grid
-
- */
- if(mygets(buf,BUFSIZE,file,ofile)==0)
- {printf("failure on reading input file header");
- exit(1);
- }
- /* printf("1st input line:%s",buf); */
- sscanf(buf,"%F %F %d",&xmin,&xmax,&w);
- if(mygets(buf,BUFSIZE,file,ofile)==0)
- {printf("failure on reading input file header");
- exit(1);
- }
- /* printf("2nd input line:%s",buf); */
- sscanf(buf,"%F %F %d",&ymin,&ymax,&h);
- if(w<2 || h<2)
- {printf("invalid data header... width or height too small\n");
- exit(1);
- }
- ex=(xmax-xmin)/(w-1);
- ey=(ymax-ymin)/(h-1);
- if(ex==0. || ey==0.)
- {printf("invalid data header... xmin==xmax or ymin==ymax\n");
- exit(1);
- }
- slope=ey/ex;
- if(ey<ex) eps=ey;
- else eps=ex;
- eps=eps*eps*1.e-4;
- /*
- printf("xmin=%g xmax=%g ex=%g w=%d\n",
- xmin,xmax,ex,w);
- printf("ymin=%g ymax=%g ey=%g h=%d\n",
- ymin,ymax,ey,h);
- */
- if(h<2||w<2)
- {fprintf(stderr,"parameter too small: height=%d, width=%d",h,w);
- exit(1);
- }
- hw=h*w;
- w2=w*2;
- hw2=hw*2;
- bottom_row=hw2-w*4;
- num_points=4*(w+h);
- x=malloc(num_points*sizeof(double));
- y=malloc(num_points*sizeof(double));
- z=malloc(hw*sizeof(double));
- mark=malloc(hw*2);
- if(x==0 || y==0 || z==0 || mark==0)
- {fprintf(stderr,"can\'t allocate buffers"); exit();
- }
- k=0;
- while(k<hw)
- {if(fscanf(file,"%F",&z[k])==-1) exit();
- switch(z_arguments)
- {case 0:if(z[k]<zmin) zmin=z[k];
- case 1: if(z[k]>zmax) zmax=z[k];
- case 2: k++;
- }
- }
- printf("writing output to %s\n",outname);
- }
-
- /* get_parameter - process one command line option
- (return # parameters used) */
- get_parameter(argc,argv) int argc; char **argv;
- { int i;
- if(streq(*argv,"-d")) {debugging=1; return 1;}
- else if(streq(*argv,"-n"))
- {if((argc>1) && numeric(argv[1])) contours=atoi(argv[1]);
- return 2;
- }
- else if(streq(*argv,"-o"))
- {argv++;
- if(argc>1 && **argv!='-')
- {strcpy(outname,*argv);
- return 2;
- }
- fprintf(stderr,"missing argument for -o switch");
- }
- else if(streq(*argv,"-v"))
- {i=get_double(argc,argv,1,&voltage,&voltage,&voltage);
- if(i && fabs(voltage)>1.e-6) calculating_capacitance++;
- return i;
- }
- else if(streq(*argv,"-z"))
- {i=get_double(argc,argv,2,&zmin,&zmax,&zmax);
- z_arguments=i-1;
- if(z_arguments>2) z_arguments=2;
- else if(z_arguments<0) z_arguments=0;
- return i;
- }
- else gripe(argv);
- }
-
- help()
- { fprintf(stderr,"contour version %s",VERSION);
- fprintf(stderr,"\nusage: contour [file] [options]\n");
- fprintf(stderr,"options are:\n");
- fprintf(stderr," -n num approximate number of contours (default %d) \n",contours);
- fprintf(stderr," -o name specify name of output file \n");
- fprintf(stderr," -v voltage calculate capacitance assuming this \n");
- fprintf(stderr," voltage between the two boundaries\n");
- fprintf(stderr," -z [min [max]] specify range of contours\n");
- exit();
- }
-
- flush_contour(zval) double zval;
- { int i;
- i=0;
- while(1)
- {error=fprintf(ofile,"%8.3g %8.3g",x[i],y[i]);
- if(error==-1) quit();
- if(++i>=np) break;
- error=fprintf(ofile,"\n");
- if(error==-1) quit();
- }
- printf(" Integral of (gradient dot normal) is %7.2g\n",integral/ey);
- strcat(buf,"\n");
- fputs(buf,ofile);
- error=fprintf(ofile,"; integral of (gradient dot normal) was %7.2g",integral/ey);
- if(error==-1) quit();
- if(calculating_capacitance)
- printf(" -> C =%7.2g pF/m\n",1e12*8.85e-12/voltage*integral/ey);
- else
- printf("\n");
- integral=0.;
- np=0;
- }
-
- quit()
- { fprintf(stderr,"output file error\n");
- fclose(ofile);
- exit(1);
- }
-